// utils/mqtt-client.js
const onenetConfig = require('./onenet-config.js')

class MQTTClient {
  constructor() {
    this.client = null
    this.isConnected = false
    this.reconnectTimer = null
    this.messageCallbacks = new Map()
    this.connectionCallbacks = []
  }

  // 初始化 MQTT 连接
  async connect() {
    return new Promise((resolve, reject) => {
      try {
        // 创建 MQTT 客户端
        this.client = wx.connectSocket({
          url: `ws://${onenetConfig.mqtt.host}:${onenetConfig.mqtt.port}/mqtt`,
          header: {
            'content-type': 'application/json'
          },
          protocols: ['mqtt']
        })

        // 监听连接打开
        this.client.onOpen(() => {
          console.log('MQTT 连接已建立')
          this.isConnected = true
          this.onConnectionStateChange(true)
          
          // 订阅主题
          this.subscribeToTopics()
          resolve()
        })

        // 监听消息接收
        this.client.onMessage((res) => {
          console.log('收到 MQTT 消息:', res)
          this.handleMessage(res)
        })

        // 监听连接关闭
        this.client.onClose(() => {
          console.log('MQTT 连接已关闭')
          this.isConnected = false
          this.onConnectionStateChange(false)
          this.scheduleReconnect()
        })

        // 监听连接错误
        this.client.onError((error) => {
          console.error('MQTT 连接错误:', error)
          this.isConnected = false
          this.onConnectionStateChange(false, error)
          reject(error)
        })

      } catch (error) {
        console.error('MQTT 连接初始化失败:', error)
        reject(error)
      }
    })
  }

  // 订阅主题
  subscribeToTopics() {
    const { productId, deviceName } = onenetConfig.product
    const topics = [
      onenetConfig.topics.deviceCommand.replace('{productId}', productId).replace('{deviceName}', deviceName),
      onenetConfig.topics.propertyGet.replace('{productId}', productId).replace('{deviceName}', deviceName)
    ]

    topics.forEach(topic => {
      this.subscribe(topic)
    })
  }

  // 订阅主题
  subscribe(topic) {
    if (!this.isConnected) {
      console.warn('MQTT 未连接，无法订阅主题')
      return
    }

    this.client.send({
      data: JSON.stringify({
        cmd: 'subscribe',
        topics: [topic]
      })
    })
    console.log('已订阅主题:', topic)
  }

  // 取消订阅
  unsubscribe(topic) {
    if (!this.isConnected) {
      console.warn('MQTT 未连接，无法取消订阅')
      return
    }

    this.client.send({
      data: JSON.stringify({
        cmd: 'unsubscribe',
        topics: [topic]
      })
    })
    console.log('已取消订阅主题:', topic)
  }

  // 发布消息
  publish(topic, message) {
    if (!this.isConnected) {
      console.warn('MQTT 未连接，无法发布消息')
      return false
    }

    try {
      const payload = typeof message === 'string' ? message : JSON.stringify(message)
      
      this.client.send({
        data: JSON.stringify({
          cmd: 'publish',
          topic: topic,
          payload: payload
        })
      })
      
      console.log('消息已发布:', { topic, message })
      return true
    } catch (error) {
      console.error('发布消息失败:', error)
      return false
    }
  }

  // 处理接收到的消息
  handleMessage(res) {
    try {
      const data = JSON.parse(res.data)
      console.log('解析后的消息:', data)

      if (data.cmd === 'publish' && data.payload) {
        const payload = JSON.parse(data.payload)
        const topic = data.topic

        // 触发消息回调
        this.triggerMessageCallbacks(topic, payload)
      }
    } catch (error) {
      console.error('处理 MQTT 消息失败:', error)
    }
  }

  // 注册消息回调
  onMessage(topic, callback) {
    if (!this.messageCallbacks.has(topic)) {
      this.messageCallbacks.set(topic, [])
    }
    this.messageCallbacks.get(topic).push(callback)
  }

  // 移除消息回调
  offMessage(topic, callback) {
    if (this.messageCallbacks.has(topic)) {
      const callbacks = this.messageCallbacks.get(topic)
      const index = callbacks.indexOf(callback)
      if (index > -1) {
        callbacks.splice(index, 1)
      }
    }
  }

  // 触发消息回调
  triggerMessageCallbacks(topic, payload) {
    if (this.messageCallbacks.has(topic)) {
      const callbacks = this.messageCallbacks.get(topic)
      callbacks.forEach(callback => {
        try {
          callback(payload, topic)
        } catch (error) {
          console.error('执行消息回调失败:', error)
        }
      })
    }
  }

  // 连接状态变化回调
  onConnectionStateChange(connected, error = null) {
    this.connectionCallbacks.forEach(callback => {
      try {
        callback(connected, error)
      } catch (err) {
        console.error('执行连接状态回调失败:', err)
      }
    })
  }

  // 注册连接状态回调
  onConnectionChange(callback) {
    this.connectionCallbacks.push(callback)
  }

  // 断开连接
  disconnect() {
    if (this.reconnectTimer) {
      clearTimeout(this.reconnectTimer)
      this.reconnectTimer = null
    }

    if (this.client) {
      this.client.close()
      this.client = null
    }
    
    this.isConnected = false
    console.log('MQTT 连接已断开')
  }

  // 重连机制
  scheduleReconnect() {
    if (this.reconnectTimer) {
      clearTimeout(this.reconnectTimer)
    }

    this.reconnectTimer = setTimeout(() => {
      console.log('尝试重新连接 MQTT...')
      this.connect().catch(error => {
        console.error('重连失败:', error)
        this.scheduleReconnect()
      })
    }, 5000) // 5秒后重连
  }

  // 上报设备数据
  reportDeviceData(data) {
    const { productId, deviceName } = onenetConfig.product
    const topic = onenetConfig.topics.deviceData
      .replace('{productId}', productId)
      .replace('{deviceName}', deviceName)

    const payload = {
      id: Date.now(),
      version: '1.0',
      params: data
    }

    return this.publish(topic, payload)
  }

  // 上报设备属性
  reportDeviceProperty(properties) {
    const { productId, deviceName } = onenetConfig.product
    const topic = onenetConfig.topics.deviceProperty
      .replace('{productId}', productId)
      .replace('{deviceName}', deviceName)

    const payload = {
      id: Date.now(),
      version: '1.0',
      params: properties
    }

    return this.publish(topic, payload)
  }

  // 获取连接状态
  getConnectionStatus() {
    return {
      connected: this.isConnected,
      host: onenetConfig.mqtt.host,
      clientId: onenetConfig.mqtt.clientId
    }
  }
}

module.exports = new MQTTClient()